#ifndef SYSTEMS_H
#define SYSTEMS_H
#include <entityx/entityx.h>
#include "Singleton.h"
#include <OIS/OIS.h>
#include "Messages.h"
#include <OGRE/Ogre.h>
#include <iostream>
using namespace entityx;

struct RenderingSystem : System<RenderingSystem>
{

    void loadResources()
    {
        Ogre::ConfigFile cf;
        cf.load("resources.cfg");
        Ogre::ConfigFile::SectionIterator seci = cf.getSectionIterator();

        Ogre::String secName, typeName, archName;

        while( seci.hasMoreElements() )
        {
            secName = seci.peekNextKey();
            Ogre::ConfigFile::SettingsMultiMap *settings = seci.getNext();
            Ogre::ConfigFile::SettingsMultiMap::iterator it;

            for( it = settings->begin(); it != settings->end(); ++it)
            {
                typeName = it->first;
                archName = it->second;
                std::cout << archName << " " << typeName << " " << secName << std::endl;
                Ogre::ResourceGroupManager::getSingleton().addResourceLocation(archName, typeName, secName);

            }
        }

    }

    void configure(ptr<EventManager> events) override
    {

        mRoot = new Ogre::Root();

        loadResources();


        if(!mRoot->restoreConfig())
            if(!mRoot->showConfigDialog())
                throw Ogre::Exception(0, "Errore nel caricare la configurazione","RenderSystem::configure");

        mSceneMgr = mRoot->createSceneManager(Ogre::ST_GENERIC, "MainSceneManager");
        mWindow = mRoot->initialise(true, "'O gioc");

        Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();

    }

    void update(ptr<EntityManager> entities, ptr<EventManager> events, double dt) override
    {
        mRoot->renderOneFrame();
    }

    Ogre::Root* mRoot;
    Ogre::RenderWindow* mWindow;
    Ogre::SceneManager* mSceneMgr;
};


struct InputSystem : System<InputSystem>, public OIS::KeyListener, public OIS::MouseListener
{

    void configure(ptr<EventManager> events) override
    {
        OIS::ParamList pl;

        Ogre::RenderWindow *window = Ogre::Root::getSingletonPtr()->getAutoCreatedWindow();


        std::ostringstream windowHndStr;
        size_t windowHnd = 0;

        window->getCustomAttribute("WINDOW", &windowHnd);

        windowHndStr << windowHnd;

        pl.insert(std::make_pair(std::string("WINDOW"),windowHndStr.str()));
        pl.insert(std::make_pair(std::string("x11_mouse_grab"), std::string("false")));
        pl.insert(std::make_pair(std::string("x11_keyboard_grab"), std::string("false")));

        mInputMgr = OIS::InputManager::createInputSystem(pl);

        mKeyboard = static_cast<OIS::Keyboard*>(mInputMgr->createInputObject(OIS::OISKeyboard, true));
        mMouse = static_cast<OIS::Mouse*>(mInputMgr->createInputObject(OIS::OISMouse, true));

        mKeyboard->setEventCallback(this);
        mMouse->setEventCallback(this);

        mEvents = events.get();
    }

    void update(ptr<EntityManager> entities, ptr<EventManager> events, double dt) override
    {
        mKeyboard->capture();
        mMouse->capture();
    }


    bool keyPressed(const OIS::KeyEvent &arg)
    {
        switch(arg.key)
        {
        case OIS::KC_W:
            mEvents->emit<Intent>(Intent::MOVE_FORWARD);
            break;
        case OIS::KC_S:
            mEvents->emit<Intent>(Intent::MOVE_BACKWARD);
            break;
        }
    }

    bool keyReleased(const OIS::KeyEvent &arg)
    {

    }

    bool mouseMoved(const OIS::MouseEvent &arg)
    {

    }

    bool mousePressed(const OIS::MouseEvent &arg, OIS::MouseButtonID id)
    {

    }

    bool mouseReleased(const OIS::MouseEvent &arg, OIS::MouseButtonID id)
    {

    }

    OIS::InputManager* mInputMgr;
    OIS::Keyboard* mKeyboard;
    OIS::Mouse* mMouse;
    EventManager* mEvents;
};



struct DebugSystem : System<DebugSystem>, Receiver<DebugSystem>
{
    void configure(ptr<EventManager> events)
    {
        events->subscribe<Intent>(*this);
    }

    void update(ptr<EntityManager> entities, ptr<EventManager> events, double dt) override {}
    void receive(const Intent &intent)
    {
        std::cout << intent.action << std::endl;
    }

};


struct GuiSystem : System<GuiSystem>, Receiver<GuiSystem>
{

};

#endif // SYSTEMS_H
